#!/bin/bash
# Gitee项目一键部署工具 - Shell版
# 此脚本整合了项目的所有功能，专注于Gitee项目的部署

# 设置一些基础变量
SERVER_PORT=3000
LOG_FILE="deploy.log"

# 创建日志文件
touch $LOG_FILE
echo "$(date): 部署服务器启动" >> $LOG_FILE

# 检查是否安装了必要的软件
check_dependencies() {
    local dependencies=("git" "python3" "pip")
    local missing=()
    
    for dep in "${dependencies[@]}"; do
        if ! command -v "$dep" &> /dev/null; then
            missing+=("$dep")
        fi
    done
    
    if [ ${#missing[@]} -gt 0 ]; then
        echo "错误: 缺少以下依赖项: ${missing[*]}"
        echo "请先安装这些依赖项再继续。"
        echo "可以运行以下命令安装它们:"
        echo "sudo apt update"
        echo "sudo apt install -y git python3 python3-pip"
        exit 1
    fi
}

# 安装Python依赖项
install_py_dependencies() {
    echo "正在安装Python依赖项..."
    
    # 检查是否有requirements.txt文件
    if [ -f "requirements.txt" ]; then
        pip install -r requirements.txt
    else
        # 如果没有requirements.txt文件，安装必要的依赖
        pip install fastapi uvicorn pydantic jinja2
    fi
    
    echo "Python依赖项已安装完成。"
}

# 生成前端HTML文件
generate_frontend_html() {
    echo "正在生成前端界面..."
    
    # 确保static目录存在
    mkdir -p static
    
    # 创建HTML文件
    cat > static/index.html << 'EOL'
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Gitee项目一键部署</title>
    <style>
        body {
            font-family: 'Arial', sans-serif;
            line-height: 1.6;
            margin: 0;
            padding: 20px;
            background-color: #f5f5f5;
            color: #333;
        }
        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 8px;
            box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
        }
        h1 {
            color: #2c3e50;
            text-align: center;
            margin-bottom: 30px;
            border-bottom: 2px solid #3498db;
            padding-bottom: 10px;
        }
        .form-group {
            margin-bottom: 20px;
        }
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: bold;
        }
        input[type="text"] {
            width: 100%;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 4px;
            box-sizing: border-box;
            font-size: 16px;
        }
        .hint {
            color: #666;
            font-size: 0.9em;
            margin-top: 5px;
        }
        .path-info {
            background-color: #e9f7fe;
            padding: 10px 15px;
            border-radius: 4px;
            margin: 15px 0;
            font-size: 0.95em;
            color: #0277bd;
            border-left: 3px solid #03a9f4;
        }
        .btn {
            background-color: #3498db;
            color: white;
            border: none;
            padding: 12px 20px;
            font-size: 16px;
            cursor: pointer;
            border-radius: 4px;
            width: 100%;
            transition: background-color 0.3s;
        }
        .btn:hover {
            background-color: #2980b9;
        }
        .btn:disabled {
            background-color: #95a5a6;
            cursor: not-allowed;
        }
        .status {
            margin-top: 20px;
            padding: 15px;
            border-radius: 4px;
            display: none;
        }
        .success {
            background-color: #d4edda;
            color: #155724;
        }
        .warning {
            background-color: #fff3cd;
            color: #856404;
        }
        .error {
            background-color: #f8d7da;
            color: #721c24;
        }
        pre {
            background-color: #f8f9fa;
            padding: 15px;
            border-radius: 5px;
            overflow-x: auto;
            margin-top: 20px;
            border: 1px solid #ddd;
            white-space: pre-wrap;
        }
        .version {
            text-align: center;
            margin-top: 20px;
            font-size: 12px;
            color: #666;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Gitee项目一键部署工具</h1>
        
        <div class="form-group">
            <label for="domain">域名:</label>
            <input type="text" id="domain" placeholder="例如: app.example.com (可选)" required>
            <div class="hint">如需配置域名访问，请输入完整域名</div>
        </div>
        
        <div class="form-group">
            <label for="gitrepo">Gitee 项目名:</label>
            <input type="text" id="gitrepo" placeholder="例如: username/repo-name 或 https://gitee.com/username/repo-name" required>
            <div class="hint">可以输入项目路径或完整URL，如有https://gitee.com前缀会自动处理</div>
        </div>
        
        <div class="path-info">
            注意: 项目将自动部署到 <strong>/projects/仓库名</strong> 目录下
        </div>
        
        <div class="form-group">
            <label for="command">运行命令:</label>
            <input type="text" id="command" placeholder="例如: npm install && npm start" required>
            <div class="hint">部署后要执行的命令</div>
        </div>
        
        <button class="btn" id="deployBtn">一键部署</button>
        
        <div class="status" id="status"></div>
        <pre id="output"></pre>
        
        <div class="version">Gitee项目部署工具 v1.0</div>
    </div>

    <script>
        document.getElementById('deployBtn').addEventListener('click', function() {
            const domain = document.getElementById('domain').value.trim();
            const gitrepo = document.getElementById('gitrepo').value.trim();
            const command = document.getElementById('command').value.trim();
            
            // 验证输入
            if (!gitrepo || !command) {
                showStatus('请填写Gitee项目和运行命令', false);
                return;
            }
            
            // 显示正在部署状态
            showStatus('正在部署，请稍候...', true);
            document.getElementById('deployBtn').disabled = true;
            
            // 发送部署请求
            fetch('/deploy', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    domain: domain,
                    gitrepo: gitrepo,
                    command: command
                })
            })
            .then(response => {
                if (!response.ok) {
                    throw new Error(`HTTP错误! 状态: ${response.status}`);
                }
                return response.json();
            })
            .then(data => {
                if (data.success) {
                    let successMsg = '部署成功!';
                    
                    // 显示项目路径
                    if (data.project_path) {
                        successMsg += ` 项目已部署到 ${data.project_path}`;
                    }
                    
                    showStatus(successMsg, true);
                    document.getElementById('output').textContent = data.output;
                } else {
                    showStatus('部署失败: ' + (data.error || '未知错误'), false);
                    document.getElementById('output').textContent = data.output || '';
                }
            })
            .catch(error => {
                showStatus('请求错误: ' + error.message, false);
            })
            .finally(() => {
                document.getElementById('deployBtn').disabled = false;
            });
        });
        
        function showStatus(message, isSuccess) {
            const statusEl = document.getElementById('status');
            statusEl.textContent = message;
            statusEl.style.display = 'block';
            
            if (isSuccess) {
                statusEl.className = 'status success';
            } else {
                statusEl.className = 'status error';
            }
            
            // 滚动到状态消息
            statusEl.scrollIntoView({ behavior: 'smooth' });
        }
    </script>
</body>
</html>
EOL

    echo "前端界面已生成完成。"
}

# 生成Python主程序文件
generate_main_python() {
    echo "正在生成Python主程序..."
    
    cat > main.py << 'EOL'
import os
import subprocess
import logging
import re
from datetime import datetime
from typing import Dict, Any, Optional
import uvicorn
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    handlers=[
        logging.FileHandler("deploy.log"),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger("gitee-deploy")

# 创建 FastAPI 应用
app = FastAPI(title="Gitee项目部署工具")

# 确保 static 目录存在
os.makedirs("static", exist_ok=True)

# 挂载静态文件目录
app.mount("/static", StaticFiles(directory="static"), name="static")

# 定义请求数据模型
class DeployRequest(BaseModel):
    domain: str
    gitrepo: str
    command: str

# 处理Gitee仓库URL，移除可能的前缀并提取仓库名
def process_gitee_url(repo_url: str) -> Dict[str, str]:
    # 移除URL前缀
    if repo_url.startswith(("https://gitee.com/", "http://gitee.com/")):
        repo_path = re.sub(r'^https?://gitee\.com/', '', repo_url)
    else:
        repo_path = repo_url
    
    # 提取仓库名称 (最后一个斜杠后的部分)
    repo_name = repo_path.split('/')[-1]
    
    return {
        "full_path": repo_path,   # 完整路径 (用户名/仓库名)
        "repo_name": repo_name    # 仅仓库名
    }

# 主页路由
@app.get("/", response_class=HTMLResponse)
async def read_root():
    try:
        with open("static/index.html", "r", encoding="utf-8") as f:
            content = f.read()
        return HTMLResponse(content=content)
    except Exception as e:
        logger.error(f"读取HTML文件失败: {e}")
        raise HTTPException(status_code=500, detail="无法加载页面")

# 部署接口
@app.post("/deploy")
async def deploy(request: DeployRequest) -> Dict[str, Any]:
    logger.info(f"开始部署: {request.dict()}")
    
    # 验证输入
    if not all([request.gitrepo, request.command]):
        logger.warning("请求参数不完整")
        return {"success": False, "error": "Gitee项目和运行命令是必填的"}
    
    # 处理Gitee仓库URL
    repo_info = process_gitee_url(request.gitrepo)
    processed_repo = repo_info["full_path"]
    repo_name = repo_info["repo_name"]
    
    # 项目部署到 /projects/{repo_name} 目录
    project_folder = f"/projects/{repo_name}"
    
    # 创建部署脚本
    deploy_script = f"""#!/bin/bash
# 确保 /projects 目录存在
mkdir -p /projects

# 创建或进入项目目录
mkdir -p {project_folder}
cd {project_folder}

# 克隆或更新仓库
if [ -d ".git" ]; then
    git pull
else
    git clone https://gitee.com/{processed_repo} .
fi

# 保存域名配置（如果提供）
if [ -n "{request.domain}" ]; then
    echo "域名: {request.domain}" > config.txt
fi

# 执行用户指定的命令
{request.command}
"""
    
    # 将脚本保存到临时文件
    script_path = "/tmp/gitee_deploy.sh"
    try:
        with open(script_path, "w", encoding="utf-8") as f:
            f.write(deploy_script)
        os.chmod(script_path, 0o755)  # 添加执行权限
        
        # 执行部署脚本
        process = subprocess.Popen(
            ["bash", script_path], 
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )
        stdout, stderr = process.communicate()
        
        # 记录输出
        output = stdout + (f"\n错误输出:\n{stderr}" if stderr else "")
            
        logger.info(f"部署结果: {process.returncode}")
        if stderr:
            logger.error(f"部署错误输出: {stderr}")
        
        # 删除临时脚本
        if os.path.exists(script_path):
            os.remove(script_path)
        
        # 判断部署结果
        if process.returncode == 0:
            logger.info("部署成功")
            return {
                "success": True, 
                "output": output,
                "project_path": project_folder
            }
        else:
            logger.error(f"部署失败，退出码: {process.returncode}")
            return {
                "success": False, 
                "error": f"部署命令失败，退出码: {process.returncode}", 
                "output": output
            }
            
    except Exception as e:
        logger.exception(f"部署过程异常: {e}")
        # 清理临时文件
        if os.path.exists(script_path):
            os.remove(script_path)
        return {"success": False, "error": str(e)}

# 健康检查接口
@app.get("/health")
async def health_check():
    return {"status": "ok", "timestamp": datetime.now().isoformat()}

# 入口点
if __name__ == "__main__":
    logger.info("Gitee项目部署工具启动")
    # 启动FastAPI服务器
    uvicorn.run(app, host="0.0.0.0", port=3000)
EOL

    echo "Python主程序已生成完成。"
}

# 生成requirements.txt文件
generate_requirements_file() {
    echo "正在生成依赖项文件..."
    
    cat > requirements.txt << 'EOL'
fastapi>=0.68.0
uvicorn>=0.15.0
pydantic>=1.8.0
jinja2>=3.0.0
EOL

    echo "依赖项文件已生成完成。"
}

# 启动FastAPI服务器
start_server() {
    echo "正在启动部署服务器..."
    
    # 确保static目录存在
    mkdir -p static
    
    # 启动FastAPI服务器
    python3 main.py &
    server_pid=$!
    echo "服务器进程ID: $server_pid" >> $LOG_FILE
    
    echo "部署服务器已启动，请访问: http://localhost:$SERVER_PORT"
    echo "按 Ctrl+C 退出服务器"
    
    # 尝试自动打开浏览器（在有GUI的Linux环境下）
    if command -v xdg-open &> /dev/null; then
        xdg-open http://localhost:$SERVER_PORT &> /dev/null || true
    fi
}

# 主函数
main() {
    echo "===== Gitee项目一键部署工具 v1.0 ====="
    echo "此工具将帮助你从Gitee仓库部署项目到服务器"
    
    # 检查依赖
    check_dependencies
    
    # 生成所需文件
    generate_frontend_html
    generate_main_python
    generate_requirements_file
    
    # 安装Python依赖
    install_py_dependencies
    
    # 启动服务器
    start_server
    
    # 保持脚本运行，等待用户按Ctrl+C退出
    trap 'echo "正在关闭服务器..."; kill $(jobs -p) 2>/dev/null; echo "服务器已关闭"; exit 0' INT
    wait
}

# 执行主函数
main 